package com.mcp.weather.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mcp.weather.cache.SimpleCache;
import com.mcp.weather.config.Config;
import com.mcp.weather.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 高德天气 API 服务
 */
public class AmapWeatherService {
    private static final Logger logger = LoggerFactory.getLogger(AmapWeatherService.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_INSTANT;

    private final Config config;
    private final SimpleCache cache;
    private final HttpClient httpClient;

    public AmapWeatherService(Config config, SimpleCache cache) {
        this.config = config;
        this.cache = cache;
        this.httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMillis(config.getTimeoutMs()))
                .build();
    }

    /**
     * 查询天气
     */
    public WeatherResponse queryWeather(String city, String extensions) {
        // 参数预处理
        city = city != null ? city.trim() : null;
        extensions = (extensions != null && !extensions.trim().isEmpty()) ? extensions.trim() : "base";

        // 验证配置
        if (!config.hasAmapKey()) {
            WeatherResponse.ErrorResponse error = new WeatherResponse.ErrorResponse();
            error.setError("缺少 AMAP_KEY 配置");
            WeatherResponse.ErrorDetail detail = new WeatherResponse.ErrorDetail();
            detail.setCode("CONFIG_MISSING");
            detail.setMessage("缺少 AMAP_KEY 配置");
            detail.setProvider("amap");
            error.setErrorDetail(detail);
            return createErrorResponse(error, city, extensions);
        }

        // 参数验证
        if (city == null || city.isEmpty()) {
            WeatherResponse.ErrorResponse error = new WeatherResponse.ErrorResponse();
            error.setError("city 为必填");
            return createErrorResponse(error, null, extensions);
        }

        if (!extensions.equals("base") && !extensions.equals("all")) {
            WeatherResponse.ErrorResponse error = new WeatherResponse.ErrorResponse();
            error.setError("extensions 仅支持 base 或 all");
            return createErrorResponse(error, city, extensions);
        }

        // 检查缓存
        String cacheKey = city + "|" + extensions;
        long ttl = extensions.equals("base") ? config.getCacheTtlBaseMs() : config.getCacheTtlAllMs();
        Object cached = cache.get(cacheKey);
        if (cached != null) {
            WeatherResponse response = new WeatherResponse();
            response.setProvider("amap");
            response.setQuery(new WeatherResponse.QueryInfo(city, extensions));
            response.setData(cached);
            response.setRaw(null);
            response.setMeta(new WeatherResponse.MetaInfo(true));
            return response;
        }

        // 调用 API
        try {
            AmapApiResponse apiResponse = callAmapApi(city, extensions);
            
            // 规范化数据
            Object normalizedData;
            if (extensions.equals("base")) {
                normalizedData = normalizeBase(apiResponse);
            } else {
                normalizedData = normalizeAll(apiResponse);
            }

            if (normalizedData == null) {
                WeatherResponse.ErrorResponse error = new WeatherResponse.ErrorResponse();
                error.setError("未获取到数据");
                WeatherResponse.ErrorDetail detail = new WeatherResponse.ErrorDetail();
                detail.setCode("NO_DATA");
                detail.setMessage("未获取到数据");
                detail.setProvider("amap");
                error.setErrorDetail(detail);
                return createErrorResponse(error, city, extensions);
            }

            // 存入缓存
            cache.put(cacheKey, normalizedData, ttl);

            // 构建响应
            WeatherResponse response = new WeatherResponse();
            response.setProvider("amap");
            response.setQuery(new WeatherResponse.QueryInfo(city, extensions));
            response.setData(normalizedData);
            response.setRaw(apiResponse);
            response.setMeta(new WeatherResponse.MetaInfo(false));
            return response;

        } catch (Exception e) {
            logger.error("调用高德天气 API 失败", e);
            WeatherResponse.ErrorResponse error = new WeatherResponse.ErrorResponse();
            error.setError(e.getMessage());
            WeatherResponse.ErrorDetail detail = new WeatherResponse.ErrorDetail();
            detail.setCode(e instanceof AmapApiException ? ((AmapApiException) e).getCode() : "INTERNAL_ERROR");
            detail.setMessage(e.getMessage() != null ? e.getMessage() : "未知错误");
            detail.setProvider("amap");
            if (e instanceof AmapApiException) {
                detail.setUpstream(((AmapApiException) e).getUpstream());
            }
            error.setErrorDetail(detail);
            return createErrorResponse(error, city, extensions);
        }
    }

    /**
     * 调用高德 API
     */
    private AmapApiResponse callAmapApi(String city, String extensions) throws IOException, InterruptedException, AmapApiException {
        // 再次检查 API key（防御性编程）
        if (!config.hasAmapKey()) {
            throw new AmapApiException("缺少 AMAP_KEY 配置", "CONFIG_MISSING", new HashMap<>());
        }
        
        String url = String.format("%s/v3/weather/weatherInfo?key=%s&city=%s&extensions=%s&output=JSON",
                config.getAmapBaseUrl(),
                URLEncoder.encode(config.getAmapKey(), StandardCharsets.UTF_8),
                URLEncoder.encode(city, StandardCharsets.UTF_8),
                extensions);

        // 记录请求 URL（隐藏 key 用于调试）
        String debugUrl = url.replaceAll("key=[^&]+", "key=***");
        logger.debug("调用高德天气 API: {}", debugUrl);
        
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .timeout(Duration.ofMillis(config.getTimeoutMs()))
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));

        // 检查 HTTP 状态码
        int statusCode = response.statusCode();
        String responseBody = response.body();
        
        if (statusCode != 200) {
            logger.error("高德天气 API 返回非 200 状态码: {}, 响应体: {}", statusCode, 
                    responseBody != null && responseBody.length() > 200 ? 
                    responseBody.substring(0, 200) + "..." : responseBody);
            Map<String, Object> upstream = new HashMap<>();
            upstream.put("statusCode", statusCode);
            upstream.put("body", responseBody);
            String errorMsg = String.format("HTTP 请求失败，状态码: %d", statusCode);
            throw new AmapApiException(errorMsg, "HTTP_ERROR", upstream);
        }

        // 检查响应体是否为空
        if (responseBody == null || responseBody.trim().isEmpty()) {
            logger.error("高德天气 API 返回空响应");
            Map<String, Object> upstream = new HashMap<>();
            upstream.put("statusCode", statusCode);
            upstream.put("body", "");
            throw new AmapApiException("上游返回空响应", "UPSTREAM_EMPTY", upstream);
        }

        // 解析 JSON
        AmapApiResponse apiResponse;
        try {
            apiResponse = objectMapper.readValue(responseBody, AmapApiResponse.class);
        } catch (Exception e) {
            // 记录完整的响应内容用于调试（限制长度避免日志过大）
            String responsePreview = responseBody != null && responseBody.length() > 2000 ? 
                    responseBody.substring(0, 2000) + "..." : responseBody;
            logger.error("解析高德天气 API 响应失败");
            logger.error("异常类型: {}", e.getClass().getName());
            logger.error("异常消息: {}", e.getMessage());
            logger.error("响应体内容 (前2000字符): {}", responsePreview);
            logger.error("Content-Type: {}", response.headers().firstValue("Content-Type").orElse("未设置"));
            logger.error("请求 URL (隐藏 key): {}", url.replaceAll("key=[^&]+", "key=***"));
            logger.error("完整异常堆栈:", e);
            
            Map<String, Object> upstream = new HashMap<>();
            upstream.put("statusCode", statusCode);
            upstream.put("body", responseBody);
            upstream.put("contentType", response.headers().firstValue("Content-Type").orElse("未设置"));
            upstream.put("exceptionType", e.getClass().getName());
            upstream.put("exceptionMessage", e.getMessage());
            throw new AmapApiException("上游返回非 JSON: " + e.getClass().getSimpleName() + " - " + e.getMessage(), "UPSTREAM_BAD_JSON", upstream);
        }

        // 检查 API 响应状态
        if (!"1".equals(apiResponse.getStatus())) {
            Map<String, Object> upstream = new HashMap<>();
            upstream.put("status", apiResponse.getStatus());
            upstream.put("infocode", apiResponse.getInfocode());
            upstream.put("info", apiResponse.getInfo());
            throw new AmapApiException(
                    apiResponse.getInfo() != null ? apiResponse.getInfo() : "上游返回错误",
                    "UPSTREAM_ERROR",
                    upstream
            );
        }

        return apiResponse;
    }

    /**
     * 规范化实时天气数据
     */
    private RealtimeWeather normalizeBase(AmapApiResponse resp) {
        if (resp.getLives() == null || resp.getLives().isEmpty()) {
            return null;
        }

        AmapApiResponse.LiveData live = resp.getLives().get(0);
        RealtimeWeather weather = new RealtimeWeather();
        weather.setCity(live.getCity());
        weather.setAdcode(live.getAdcode());
        weather.setWeather(live.getWeather());
        
        // 转换温度
        if (live.getTemperature() != null && !live.getTemperature().isEmpty()) {
            try {
                weather.setTemperature(Integer.parseInt(live.getTemperature()));
            } catch (NumberFormatException e) {
                weather.setTemperature(null);
            }
        }
        
        weather.setWindDirection(live.getWinddirection());
        weather.setWindPower(live.getWindpower());
        
        // 转换湿度
        if (live.getHumidity() != null && !live.getHumidity().isEmpty()) {
            try {
                weather.setHumidity(Integer.parseInt(live.getHumidity()));
            } catch (NumberFormatException e) {
                weather.setHumidity(null);
            }
        }
        
        // 转换报告时间
        weather.setReportTime(toISO(live.getReporttime()));
        
        return weather;
    }

    /**
     * 规范化天气预报数据
     */
    private ForecastWeather normalizeAll(AmapApiResponse resp) {
        if (resp.getForecasts() == null || resp.getForecasts().isEmpty()) {
            return null;
        }

        AmapApiResponse.ForecastData forecast = resp.getForecasts().get(0);
        ForecastWeather weather = new ForecastWeather();
        weather.setCity(forecast.getCity());
        weather.setAdcode(forecast.getAdcode());
        weather.setReportTime(toISO(forecast.getReporttime()));

        // 转换预报列表
        if (forecast.getCasts() != null && !forecast.getCasts().isEmpty()) {
            List<ForecastWeather.ForecastItem> items = new ArrayList<>();
            for (AmapApiResponse.CastData cast : forecast.getCasts()) {
                ForecastWeather.ForecastItem item = new ForecastWeather.ForecastItem();
                item.setDate(cast.getDate());
                
                // 转换星期
                if (cast.getWeek() != null && !cast.getWeek().isEmpty()) {
                    try {
                        item.setWeek(Integer.parseInt(cast.getWeek()));
                    } catch (NumberFormatException e) {
                        item.setWeek(null);
                    }
                }
                
                // 白天天气
                ForecastWeather.DayNightInfo day = new ForecastWeather.DayNightInfo();
                day.setWeather(cast.getDayweather());
                if (cast.getDaytemp() != null && !cast.getDaytemp().isEmpty()) {
                    try {
                        day.setTemp(Integer.parseInt(cast.getDaytemp()));
                    } catch (NumberFormatException e) {
                        day.setTemp(null);
                    }
                }
                day.setWindDirection(cast.getDaywind());
                day.setWindPower(cast.getDaypower());
                item.setDay(day);

                // 夜间天气
                ForecastWeather.DayNightInfo night = new ForecastWeather.DayNightInfo();
                night.setWeather(cast.getNightweather());
                if (cast.getNighttemp() != null && !cast.getNighttemp().isEmpty()) {
                    try {
                        night.setTemp(Integer.parseInt(cast.getNighttemp()));
                    } catch (NumberFormatException e) {
                        night.setTemp(null);
                    }
                }
                night.setWindDirection(cast.getNightwind());
                night.setWindPower(cast.getNightpower());
                item.setNight(night);

                items.add(item);
            }
            weather.setForecasts(items);
        }

        return weather;
    }

    /**
     * 日期时间转换为 ISO 8601 格式
     */
    private String toISO(String timeStr) {
        if (timeStr == null || timeStr.isEmpty()) {
            return null;
        }
        try {
            // 高德 API 返回的日期格式可能是 "2024-01-01 12:00:00" 或 "2024-01-01T12:00:00"
            String normalized = timeStr.replace(" ", "T");
            LocalDateTime dateTime = LocalDateTime.parse(normalized, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            Instant instant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
            return ISO_FORMATTER.format(instant);
        } catch (Exception e) {
            logger.warn("日期时间转换失败: {}", timeStr, e);
            return timeStr;
        }
    }

    /**
     * 创建错误响应
     */
    private WeatherResponse createErrorResponse(WeatherResponse.ErrorResponse error, String city, String extensions) {
        WeatherResponse response = new WeatherResponse();
        response.setProvider("amap");
        if (city != null && extensions != null) {
            response.setQuery(new WeatherResponse.QueryInfo(city, extensions));
        }
        response.setData(null);
        response.setRaw(null);
        response.setMeta(null);
        // 将错误信息存储在 raw 字段中，以便在 WeatherMcpServer 中识别
        response.setRaw(error);
        return response;
    }

    /**
     * 高德 API 异常
     */
    public static class AmapApiException extends Exception {
        private final String code;
        private final Map<String, Object> upstream;

        public AmapApiException(String message, String code, Map<String, Object> upstream) {
            super(message);
            this.code = code;
            this.upstream = upstream;
        }

        public String getCode() {
            return code;
        }

        public Map<String, Object> getUpstream() {
            return upstream;
        }
    }
}

